class ContextualLogger {

    constructor(defaultContext = {filterLevel: LOG_LEVEL.OFF}) {
        this.context = defaultContext;
        this.setLevel(defaultContext.filterLevel);
        this.logHandler = [];
    }

    setLevel(newLevel) {
        if (newLevel && "value" in newLevel) {
            this.context.filterLevel = newLevel;
        }
    }

    enabledFor(level) {
        let filterLevel = this.context.filterLevel;
        return level.value >= filterLevel.value;
    }

    debug() {
        if (this.enabledFor(LOG_LEVEL.DEBUG)) {
            this.invoke(LOG_LEVEL.DEBUG, arguments);
        }
    }

    info() {
        if (this.enabledFor(LOG_LEVEL.INFO)) {
            this.invoke(LOG_LEVEL.INFO, arguments);
        }
    }

    warn() {
        if (this.enabledFor(LOG_LEVEL.WARN)) {
            this.invoke(LOG_LEVEL.WARN, arguments);
        }
    }

    error() {
        if (this.enabledFor(LOG_LEVEL.ERROR)) {
            this.invoke(LOG_LEVEL.ERROR, arguments);
        }
    }

    time(label) {
        if (this.enabledFor(LOG_LEVEL.TIME)) {
            if (typeof label === 'string' && label.length > 0) {
                this.invoke(LOG_LEVEL.TIME, [label, 'start']);
            }
        }
    }

    timeEnd(label) {
        if (this.enabledFor(LOG_LEVEL.TIME)) {
            if (typeof label === 'string' && label.length > 0) {
                this.invoke(LOG_LEVEL.TIME, [label, 'end']);
            }
        }
    }

    appendHandler(handler, options) {
        if (options === undefined) {
            options = {};
        }
        //如果没有设置日志等级,使用默认的日志等级
        if (options.level === undefined) {
            options.level = this.context.filterLevel;
        }
        //如果没有设置formatter; 使用默认的formatter
        if (options.formatter === undefined) {
            options.formatter = defaultMessageFormatter;
        }
        //如果Handler和Formatter都存在且都是有效函数
        if (handler != undefined && typeof handler === "function") {
            if (options.formatter && typeof options.formatter === "function") {
                $.extend(this.context, {filterLevel: options.level});
                this.logHandler.push({handle: handler, level: options.level, formatter: options.formatter});
            }
        }
    }

    invoke(level, msgArgs) {
        $.extend(this.context, {level: level});
        $.each(this.logHandler, (index, item)=> {
            try {
                if (level.value >= item.level.value) {
                    var messages = Array.prototype.slice.call(msgArgs);
                    item.formatter(messages, this.context);
                    item.handle(messages, this.context);
                }
            } catch (e) {
                //如果有错误,continue
                console.log("LOGGER ERROR!", e);
                return true;
            }
        });
    }
}

function defaultMessageFormatter(messages, context) {
    if (context.name) {
        messages.unshift(new Date().toUTCString(), "(" + context.level.name + ")", "[" + context.name + "]");
    }
}

function merge() {
    let args = arguments, target = args[0], key, i;
    for (i = 1; i < args.length; i++) {
        for (key in args[i]) {
            if (!(key in target) && args[i].hasOwnProperty(key)) {
                target[key] = args[i][key];
            }
        }
    }
    return target;
}

var loggerManager = (function () {
    let contextualLoggersByNameMap = {};
    return {
        name: "Log Manager",
        version: "2.0.0",
        get: function (name) {
            if (name.toLowerCase() == "unknown") {
                return new ContextualLogger(merge({name: name, filterLevel: LOG_LEVEL.OFF}));
            }
            if (contextualLoggersByNameMap[name]) {
                contextualLoggersByNameMap[name].logHandler = [];
                return contextualLoggersByNameMap[name];
            } else {
                contextualLoggersByNameMap[name] = new ContextualLogger(merge({
                    name: name,
                    filterLevel: LOG_LEVEL.OFF
                }));
                return contextualLoggersByNameMap[name];
            }
        }
    }
});

var LOG_LEVEL = {
    DEBUG: {value: 1, name: 'DEBUG'},
    INFO: {value: 2, name: 'INFO'},
    TIME: {value: 3, name: 'TIME'},
    WARN: {value: 4, name: 'WARN'},
    ERROR: {value: 8, name: 'ERROR'},
    OFF: {value: 99, name: 'OFF'}
};

export {loggerManager, LOG_LEVEL};